﻿using System;
using StackExchange.Redis;
using System.Collections.Generic;
using Core.Framework.Model.Common;

namespace Core.Framework.Redis.Queue_Helper
{
    public static class RedisQueueHelper
    {
        static object lockReloadFlag = new object();
        static object lockListPopByLengthFlag = new object();

        static IDatabase GetDateBase(int db, ConnectionMultiplexer conn = null)
        {
            return RedisConnectionHelper.Instance.GetDatabase(db);
        }

        #region RedisProperty

        /// <summary>
        /// 出列
        /// </summary>
        /// <param name="key"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        public static string ListPop(string key, int db = 2)
        {
            try
            {
                return GetDateBase(db).ListLeftPop(key);
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).ListLeftPop(key);
            }
        }

        /// <summary>
        /// 出栈
        /// </summary>
        /// <returns>The stack pop.</returns>
        /// <param name="key">Key.</param>
        /// <param name="db">Db.</param>
        public static string ListStackPop(string key, int db = 2)
        {
            try
            {
                return GetDateBase(db).ListRightPop(key);
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).ListRightPop(key);
            }
        }

        /// <summary>
        /// 入列
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        public static long ListPush(string key,string value, int db = 2)
        {
            try
            {
                return GetDateBase(db).ListRightPush(key, value);
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).ListRightPush(key, value);
            }
        }

        /// <summary>
        /// 获取列表数量
        /// </summary>
        /// <returns>The length.</returns>
        /// <param name="key">Key.</param>
        /// <param name="db">Db.</param>
        public static long ListLength(string key,int db = 2)
        {
            try
            {
                return GetDateBase(db).ListLength(key);
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).ListLength(key);
            }
        }

        /// <summary>
        /// 删除消息
        /// </summary>
        /// <returns>The length.</returns>
        /// <param name="key">Key.</param>
        /// <param name="db">Db.</param>
        public static long ListRemove(string key,string value, int db = 2)
        {
            try
            {
                return GetDateBase(db).ListRemove(key, value);
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).ListRemove(key, value);
            }
        }

        /// <summary>
        /// 获取列表所有数据
        /// </summary>
        /// <returns>The length.</returns>
        /// <param name="key">Key.</param>
        /// <param name="db">Db.</param>
        /// <param name="force">不满足约束</param>
        public static RedisValue[] GetListPopByLength(string key,int start,int stop, int db = 2, bool force = false)
        {
            long length = 0;
            IDatabase database;

            try
            {
                database = GetDateBase(db);

                if(!force)
                    length = database.ListLength(key);
            }
            catch
            {
                throw;
            }

            RedisValue[] result;

            if (length >= stop || force)
            {
                lock (lockListPopByLengthFlag)
                {
                    var batch = database.CreateBatch();

                    var taskResult
                        = batch.ListRangeAsync(key, start, stop);
                    batch.ListTrimAsync(key, stop + 1, -1);

                    batch.Execute();

                    result = taskResult.Result;
                }
            }
            else
                return null;

            return result;

        }


        /// <summary>
        /// 入队
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="deliverTime">排序字段</param>
        /// <param name="db"></param>
        /// <returns></returns>
        public static bool SortedPush(string key, string value,double deliverTime = 0, int db = 4)
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(2018, 1, 1, 0, 0, 0, 0);
            try
            {
                return GetDateBase(db).SortedSetAdd(key, value, ts.TotalMilliseconds + deliverTime);
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).SortedSetAdd(key, value, ts.TotalMilliseconds + deliverTime);
            }
        }

        /// <summary>
        /// 出队
        /// </summary>
        /// <param name="key"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        public static RedisValue[] SortedPop(string key, int db = 4)
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(2018, 1, 1, 0, 0, 0, 0);
            RedisValue[] values;
            try
            {
                values = GetDateBase(db).SortedSetRangeByScore(key, stop: ts.TotalMilliseconds);
                GetDateBase(db).SortedSetRemoveRangeByScore(key,start:0,stop: ts.TotalMilliseconds);
            }
            catch
            {
                throw;
                //values = ReloadRedisService(db).SortedSetRangeByScore(key, stop: ts.TotalMilliseconds);
                GetDateBase(db).SortedSetRemoveRangeByScore(key,start:0,stop: ts.TotalMilliseconds);
            }

            return values;
        }


        public static bool HashSet(string tableName, string field, string value,int db = 3)
        {
            try
            {
                return GetDateBase(db).HashSet(tableName, field, value);
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).HashSet(tableName, field, value);
            }
        }

        public static RedisValue HashGet(string tableName, string field,int db = 3)
        {
            try
            {
                return GetDateBase(db).HashGet(tableName, field);
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).HashGet(tableName, field);
            }
        }

        public static bool HashDelete(string tableName, string field, int db = 3)
        {
            try
            {
                return GetDateBase(db).HashDelete(tableName, field);
            }
            catch
            {
                throw;
                //return ReloadRedisService(db).HashDelete(tableName, field);
            }
        }

        #endregion

    }
}
